﻿// -------------------------------------------------------------------------
//    @FileName         :    NFCacheDataInsertTrans.cpp
//    @Author           :    Gao.Yi
//    @Date             :    2025-08-14
//    @Email			:    445267987@qq.com
//    @Module           :    NFCacheDataInsertTrans
//    @Desc             :    缓存数据插入事务基类实现
//                           提供缓存数据插入的统一接口，支持带Protobuf消息和不带消息两种插入方式
//                           作为子事务处理存储服务器交互，完成后回调父事务
//
// -------------------------------------------------------------------------

#include "NFCacheDataInsertTrans.h"

#include "NFCacheDataGetTrans.h"
#include "NFIServerMessageModule.h"

/**
 * @brief 构造函数，根据共享内存模式进行初始化
 * 
 * 根据共享内存管理器的创建模式选择初始化方式：
 * - EN_OBJ_MODE_INIT：冷启动模式，调用 CreateInit() 进行完整初始化
 * - 其他模式：热启动模式，调用 ResumeInit() 进行恢复初始化
 */
NFCacheDataInsertTrans::NFCacheDataInsertTrans()
{
    if (EN_OBJ_MODE_INIT == NFShmMgr::Instance()->GetCreateMode())
    {
        CreateInit();
    }
    else
    {
        ResumeInit();
    }
}

/**
 * @brief 析构函数
 * 
 * 清理资源，由于使用共享内存管理，通常无需特殊处理
 */
NFCacheDataInsertTrans::~NFCacheDataInsertTrans()
{
}

/**
 * @brief 冷启动创建初始化
 * 
 * 在共享内存冷启动场景下，对所有成员变量进行零值初始化：
 * - m_reason：调用原因/场景标识
 * - m_roleId：目标对象ID
 * - m_tableId：数据表ID
 * - m_transId：上层批量事务ID
 * - m_ullId：操作的目标ID
 * 
 * @return 0 表示成功
 */
int NFCacheDataInsertTrans::CreateInit()
{
    m_iReason = 0;
    m_ullRoleId = 0; // 目标对象ID
    m_iTableId = 0; // 数据表ID
    m_iTransId = 0; // 上层批量事务ID
    m_ullTargetId = 0;
    return 0;
}

/**
 * @brief 热启动恢复初始化
 * 
 * 在共享内存热启动场景下，从持久化数据恢复对象状态时调用
 * 当前实现为空，如有需要可在此添加恢复逻辑
 * 
 * @return 0 表示成功
 */
int NFCacheDataInsertTrans::ResumeInit()
{
    return 0;
}

/**
 * @brief 初始化事务运行参数
 * 
 * 设置事务执行所需的基本参数，通常在创建事务后立即调用
 * 
 * @param serverType 目标存储服务器类型
 * @param roleId      目标对象ID
 * @param tableId     数据表ID，用于标识要操作的数据表
 * @param transId     上层批量事务ID，用于回调时定位父事务
 * @return 0 表示成功
 */
int NFCacheDataInsertTrans::Init(int serverType, uint64_t roleId, int tableId, int transId)
{
    m_ullRoleId = roleId;
    m_iServerType = serverType;
    m_iTableId = tableId;
    m_iTransId = transId;
    return 0;
}

/**
 * @brief 处理存储服务器返回的消息
 * 
 * 根据命令类型分发处理不同的存储服务器响应消息：
 * - NF_STORESVR_S2C_INSERTOBJ：插入操作结果
 * - NF_STORESVR_S2C_SELECTOBJ：查询操作结果（插入后自动查询验证）
 * 
 * @param pSsMsgRes 存储服务器返回的 Protobuf 消息指针
 * @param cmd       消息命令类型
 * @param tableId   数据表ID，用于验证响应是否匹配当前事务
 * @param seq       消息序列号
 * @param errCode   存储服务器返回的错误码
 * @return 0 表示成功处理
 */
int NFCacheDataInsertTrans::HandleDBMsgRes(const google::protobuf::Message* pSsMsgRes, uint32_t cmd, uint32_t tableId, uint32_t seq, int32_t errCode)
{
    int iRetCode = 0;
    if ((uint32_t)m_iTableId == tableId)
    {
        if (cmd == NFrame::NF_STORESVR_S2C_INSERTOBJ)
        {
            iRetCode = InsertCacheDataRes(dynamic_cast<const NFrame::storesvr_insertobj_res*>(pSsMsgRes), errCode);
        }
        else if (cmd == NFrame::NF_STORESVR_S2C_SELECTOBJ)
        {
            iRetCode = LoadCacheDataRes(dynamic_cast<const NFrame::storesvr_selobj_res*>(pSsMsgRes), errCode);
        }
        else
        {
            LOG_ERR(0, -1, "not handle table:{} cmd:{}", tableId, cmd);
            iRetCode = -1;
        }
    }
    else
    {
        LOG_ERR(0, -1, "not handle table:{}", tableId);
        iRetCode = -1;
    }

    if (iRetCode != 0)
    {
        SetFinished(iRetCode);
    }

    return 0;
}

/**
 * @brief 事务结束回调处理
 * 
 * 当当前事务完成时，通过上层批量事务ID找到父事务并回调结果。
 * 这是事务链式调用的关键环节，确保批量操作能够正确汇总结果。
 * 
 * @param iRunLogicRetCode 事务运行逻辑的返回码
 * @return 0 表示回调成功
 */
int NFCacheDataInsertTrans::HandleTransFinished(int iRunLogicRetCode)
{
    if (m_iTransId <= 0) return 0;

    // 根据事务ID获取上层批量事务对象
    NFCacheDataGetTrans* pBatchBase = NFCacheDataGetTrans::GetTrans(m_iTransId);
    CHECK_NULL_WF(m_ullRoleId, pBatchBase, "GetTrans failed, transId:{}", m_iTransId);

    // 回调上层事务的结果处理方法
    int iRetCode = pBatchBase->OnInsertCacheDataFinish(m_ullRoleId, m_iTableId, m_iReason, iRunLogicRetCode);
    CHECK_ERR_AND_FIN_TRANS(iRetCode, pBatchBase, "{}::InsertCacheDataBatchRes Failed, ullId:{}, tableId:{}, reason:{}", pBatchBase->GetClassName(), m_ullRoleId, m_iTableId, m_iReason);

    return 0;
}

/**
 * @brief 发起缓存数据插入请求（带Protobuf消息）
 * 
 * 向存储服务器发送插入对象的事务请求：
 * 1. 保存目标ID和调用原因
 * 2. 通过消息模块发送插入请求
 * 3. 存储服务器处理完成后会回调 HandleDBMsgRes()
 * 
 * @param ullId      目标ID
 * @param iReason    调用原因/场景标识
 * @param stPbClass  Protobuf消息对象，包含要插入的数据
 * @return 0 表示成功，其他值为错误码
 */
int NFCacheDataInsertTrans::InsertCacheDataReq(uint64_t ullId, int iReason, const google::protobuf::Message& stPbClass)
{
    m_ullTargetId = ullId;
    m_iReason = iReason;
    int iRetCode = FindModule<NFIServerMessageModule>()->SendInsertObjTrans((NF_SERVER_TYPE)m_iServerType, ullId, stPbClass, this->m_iTableId, this->GetGlobalId());
    CHECK_ERR(m_ullRoleId, iRetCode, "SendInsertObjTrans Failed, roleId:{}", m_ullRoleId);
    return 0;
}

/**
 * @brief 发起缓存数据插入请求（不带Protobuf消息）
 * 
 * 虚函数，子类应重写此方法实现具体的插入逻辑。
 * 基类实现仅输出警告信息，提醒开发者需要在子类中实现。
 * 
 * @param ullId   目标ID
 * @param iReason 调用原因/场景标识
 * @return 0 表示成功
 */
int NFCacheDataInsertTrans::InsertCacheDataReq(uint64_t ullId, int iReason)
{
    LOG_WARN(0, -1, "InsertCacheDataReq not implemented, ullId: {}, iReason: {}", ullId, iReason);
    return 0;
}

/**
 * @brief 处理插入操作返回结果（基类默认实现）
 * 
 * 虚函数，子类应重写此方法实现具体的插入结果处理逻辑。
 * 基类实现仅输出警告信息，提醒开发者需要在子类中实现。
 * 
 * @param pRes     存储服务器返回的插入结果
 * @param errCode  错误码
 * @return 0 表示成功
 */
int NFCacheDataInsertTrans::InsertCacheDataRes(const NFrame::storesvr_insertobj_res* pRes, int32_t errCode)
{
    LOG_WARN(0, -1, "InsertCacheDataRes not implemented, pRes: {}, errCode: {}", pRes ? pRes->DebugString() : "nullptr", errCode);
    SetFinished(0);
    return 0;
}

/**
 * @brief 处理查询操作返回结果（基类默认实现）
 * 
 * 虚函数，子类应重写此方法实现具体的查询结果处理逻辑。
 * 基类实现仅输出警告信息，提醒开发者需要在子类中实现。
 * 
 * @param pRes     存储服务器返回的查询结果
 * @param errCode  错误码
 * @return 0 表示成功
 */
int NFCacheDataInsertTrans::LoadCacheDataRes(const NFrame::storesvr_selobj_res* pRes, int32_t errCode)
{
    LOG_WARN(0, -1, "LoadCacheDataRes not implemented, pRes: {}, errCode: {}", pRes ? pRes->DebugString() : "nullptr", errCode);
    SetFinished(0);
    return 0;
}


